package com.um.jdy.ykc.command;

import cn.hutool.core.util.ArrayUtil;
import com.um.jdy.ykc.utils.RadixsUtil;
import com.um.jdy.ykc.utils.YkcCRC16Util;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Data;

import java.io.Serializable;

/**
 * 云快充命令基类
 *
 * @author 甘天伟
 * @since 2022/6/27
 * 版权所有 广州优匠科技有限公司
 */
@Data
public class YkcCommand implements Serializable {

    protected int beginField;//起始标识:1个字节
    protected int length;//数据长度:1个字节
    protected int serial;//序列号域:2个字节
    protected int encFlag;//加密标志:1个字节
    protected int command;//帧类型标志:1个字节
    protected byte[] data;//数据域，子类需要重新解析
    protected int verify;//帧校验域:2个字节

    public YkcCommand(){
        beginField = RadixsUtil.hexToInteger("68");
    }

    /**
     * 构造函数末尾调用
     */
    protected void postConstruct() {
        this.length = getDataLength();
        this.verify = getVerifyCode();
    }

    /**
     * 读取指定下标的字节数组
     * @param bytes 源字节
     * @param beginIndex 起始座标
     * @param length 字节数组长度
     * @return
     */
    protected byte[] readBytes(byte[] bytes,int beginIndex,int length){
        byte[] newBytes = new byte[length];
        int numIndex = 0;
        for(int index = beginIndex;index < beginIndex +length ;index ++){
            newBytes[numIndex] = bytes[index];
            numIndex ++;
        }
        return newBytes;
    }

    /**
     * 读取指定下标的字节数组
     * @param bytes 源字节
     * @param beginIndex 起始座标
     * @param length 字节数组长度
     * @param reverse 是否反转数组
     * @return
     */
    protected byte[] readBytes(byte[] bytes, int beginIndex, int length, boolean reverse) {
        byte[] newBytes = new byte[length];
        int numIndex = 0;
        for(int index = beginIndex;index < beginIndex +length ;index ++){
            newBytes[numIndex] = bytes[index];
            numIndex ++;
        }
        return reverse ? ArrayUtil.reverse(newBytes) : newBytes;
    }

    /**
     * 写入指定下标的字节数组
     * @param bytes 源字节
     * @param beginIndex 起始座标
     * @param bytes 需要写入字节数组
     * @return
     */
    protected void writeBytes(byte[] bytes,int beginIndex,byte[] writeData){
        int numIndex = beginIndex;
        for(int index = 0;index < writeData.length ;index ++){
            bytes[numIndex] = writeData[index];
            numIndex ++;
        }
    }

    /**
     * 创建字节数组
     * @param size 字节大小
     * @return
     */
    protected byte[] createBytes(int size){
        byte[] bytes = new byte[size];
        for(int index = 0;index < size;index ++){
            bytes[index] = 0;
        }
        return bytes;
    }

    /**
     * 填充指定长度的0字节数组
     * @param source 源字节
     * @param size 填充长度
     * @return
     */
    protected byte[] fillZeroBytes(byte[] source,int size){
        byte[] bytes = new byte[source.length + size];
        for(int index = 0;index < source.length;index ++){
            bytes[index] = source[index];
        }
        for(int index = source.length;index < source.length+size;index ++){
            bytes[index] = 0;
        }
        return bytes;
    }

    /**
     * 去掉字节数组右边填充的0
     * @param sources 源字节数组
     * @return
     */
    protected byte[] trimBytes(byte[]  sources){
        int len = 0;
        for(int index = sources.length -1 ;index >= 0;index --){
            if(sources[index] != 0){
                len = index + 1;
                break;
            }
        }

        byte[] newBytes = new byte[len];
        for(int index = 0;index < len;index ++){
            newBytes[index] = sources[index];
        }

        return newBytes;
    }

    /**
     * 对象转为字节数组
     * @return
     */
    public byte[] toBytes(){
        ByteBuf buff = Unpooled.buffer();
        buff.writeByte(beginField);
        buff.writeByte(length);
        buff.writeBytes(ArrayUtil.reverse(RadixsUtil.int16ToBytes(serial)));
        buff.writeByte(encFlag);
        buff.writeByte(command);
        buff.writeBytes(data);
        buff.writeBytes(RadixsUtil.int16ToBytes(verify));

        byte[] bytes = new byte[buff.readableBytes()];
        buff.readBytes(bytes);
        buff.release();
        return bytes;
    }

    /**
     * 字节数组转为对象
     * @return
     */
    public void parseBytes(byte[] bytes){
        beginField = RadixsUtil.byteToInteger(bytes[0]);
        length = RadixsUtil.byteToInteger(bytes[1]);
        serial = RadixsUtil.bytesToInteger(ArrayUtil.reverse(readBytes(bytes,2,2)));
        encFlag = RadixsUtil.byteToInteger(bytes[4]);
        command = RadixsUtil.byteToInteger(bytes[5]);
        data = readBytes(bytes,6,bytes.length - 8);
        verify = RadixsUtil.bytesToInteger(readBytes(bytes,bytes.length - 2,2));
    }

    public int getDataLength(){
        return 4 + data.length;
    }

    /**
     * 生成校验码
     * @return
     */
    public int getVerifyCode(){
        ByteBuf buff = Unpooled.buffer();
        buff.writeBytes(ArrayUtil.reverse(RadixsUtil.int16ToBytes(serial)));
        buff.writeByte(encFlag);
        buff.writeByte(command);
        buff.writeBytes(data);

        byte[] bytes = new byte[buff.readableBytes()];
        buff.readBytes(bytes);
        buff.release();

        return YkcCRC16Util.getCRC16(bytes);
    }

    /**
     * 判断校验码是否正确
     * @return
     */
    public boolean equalsVerify(){
        return getVerifyCode() == verify;
    }
}
